Conversation
|
|
||
| println!("🔍 Fetching your assigned issues..."); | ||
| match get_my_issues(&JiraClient::new(&config), project.as_deref(), all).await { | ||
| Ok(issues) => { |
There was a problem hiding this comment.
Ok(issues) if issues.is_empty() => {1}
Ok(issues) => {2}
src/jira_client.rs
Outdated
| pub async fn get_my_issues( | ||
| jira_client: &JiraClient, | ||
| project: Option<&str>, | ||
| include_done: bool, |
There was a problem hiding this comment.
В сервис просочился пользовательский флаг. Стоит enum сделать и выбирать его элементы в зависимости от флага пользователя из команды
src/jira_client.rs
Outdated
| project: Option<&str>, | ||
| include_done: bool, | ||
| ) -> Result<Vec<Issue>, JiraClientError> { | ||
| let mut jql = "assignee = currentUser()".to_string(); |
There was a problem hiding this comment.
сбор jql если вынести в отдельную функцию (а лучше Trait builder) и даже можно тестами отдельно покрыть.
src/jira_client.rs
Outdated
| ); | ||
|
|
||
| let mut all_issues = Vec::new(); | ||
| let max_results = 50; |
There was a problem hiding this comment.
можно в const вынести на уровень модуля
| jql.push_str(" ORDER BY updated DESC"); | ||
|
|
||
| let api_url = format!( | ||
| "{}/rest/api/2/search", |
There was a problem hiding this comment.
nit: можно использовать тип Url и соединять в него пути вместо форматирования строчек.
src/jira_client.rs
Outdated
| let search_response: SearchResponse = | ||
| response.json().await.map_err(|_| JiraClientError::Parse)?; | ||
|
|
||
| let fetched = search_response.issues.len() as i32; |
There was a problem hiding this comment.
а зачем так много, i16 не хватит? также подходит usize
|
|
||
| #[derive(Debug, Clone)] | ||
| pub struct JqlBuildError { | ||
| pub message: String, |
There was a problem hiding this comment.
А лучше enum с thiserror, чем разные сообщения, которые не разбиты по кейсам
| impl std::error::Error for JqlBuildError {} | ||
|
|
||
| /// Project keys must be uppercase alphanumeric + underscore only. | ||
| fn validate_project_key(key: &str) -> Result<(), JqlBuildError> { |
There was a problem hiding this comment.
parse dont validate. Тут стоит завести тип ProjectKey(String), который парсится из &str, String через FromString, TryFrom (как удобнее)
|
|
||
| /// Build the final JQL string. | ||
| pub fn build(self) -> String { | ||
| let mut jql = String::new(); |
There was a problem hiding this comment.
Тут мутация строки и ниже цикл foreach. Для раста это малость неоптимально и будет сводить компилятор с ума, так как нет оптимизаций итераторами. Предлагаю использовать коллекцию conditions через iter, каждое значение смаппить в строчку через map(|conj| write!(...)) и после всего этого применить join на результат итератора
| let _ = write!(jql, "{} {} {}", cond.field, cond.operator, cond.value); | ||
| } | ||
|
|
||
| if !self.order_by.is_empty() { |
There was a problem hiding this comment.
вижу, что в два-три этапа собирается jql, но можно все разные части в разных переменных строк собрать. А на выходе соединить все части эти. Сборка разных частей строк спокойно делится на функции приватные и для них можно писать десты в docstring :)
| /// Add a condition joined by OR. | ||
| #[allow(dead_code)] | ||
| pub fn or(mut self, field: Field, op: Operator, value: Value) -> Self { | ||
| let conjunction = if self.conditions.is_empty() { |
There was a problem hiding this comment.
self.conditions.is_empty().then(|| Some(Conjunction::Or))
|
|
||
| /// Right-hand side value in a JQL condition. | ||
| #[derive(Debug, Clone)] | ||
| #[allow(dead_code)] |
|
|
||
| /// Add a condition joined by AND (or as the first condition). | ||
| pub fn and(mut self, field: Field, op: Operator, value: Value) -> Self { | ||
| let conjunction = if self.conditions.is_empty() { |
There was a problem hiding this comment.
self.conditions.is_empty().then(|| Some(Conjunction::AND))
No description provided.